﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using System.IO;
using System.ComponentModel;
using System;

public class DownloadManager
{

    private Thread thread;

    private string mRemoteFile;
    private string mLocalFile;

    private System.DateTime mRemoteLastModified;
    private System.DateTime mLocalLastModified;

    private long mRemoteFileSize = 0;
    private bool mHadError = false;

    private bool mIsDone = false;
    private bool mIsRun = false;
    private bool mAbort = false;

    public DownloadManager(string remoteFile, string localFile)
    {
        mRemoteFile = remoteFile;
        mLocalFile = localFile;
        thread = new Thread(() => Download());
    }


    public void Start()
    {
        thread.Start();
    }

    public void Abort()
    {
        mIsRun = false;
        mAbort = true;
    }

    public bool isDone
    {
        get { return mIsDone; }
    }

    public float process
    {
        get;
        set;
    }

    public bool debug
    {
        get;
        set;
    }

    public bool IsOutdated
    {
        get
        {
            if (File.Exists(mLocalFile))
                return mRemoteLastModified > mLocalLastModified;
            return true;
        }
    }

    private void Download()
    {
        GetHead();
        GetContent();
    }

    private void GetHead()
    {
        if (File.Exists(mLocalFile))
        { // This will not work in web player!
            mLocalLastModified = File.GetLastWriteTime(mLocalFile);
        }

        HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(mRemoteFile);
        request.Method = "HEAD"; // Only the header info, not full file!

        // Get response will throw WebException if file is not found
        HttpWebResponse resp = null;
        try
        {
            resp = (HttpWebResponse)request.GetResponse();
        }
        catch (System.Exception e)
        {
            Debug.LogWarning("<color=red>ERROR: " + mRemoteFile + "</color>");
            Debug.LogWarning("ERROR: " + e);
            //Log("Constructor Exception: " + e);
            mHadError = true;
            return;
        }

        mRemoteLastModified = resp.LastModified;
        mRemoteFileSize = resp.ContentLength;

        Log("[GetHead]mRemoteFileSize:" + mRemoteFileSize);
        resp.Close();
    }

    private void GetContent()
    {
        if (mHadError) { return; }
        if (mIsRun) { return; }

        mIsRun = true;

        long localFileSize = (File.Exists(mLocalFile)) ? (new FileInfo(mLocalFile)).Length : 0;

        if (localFileSize == mRemoteFileSize && !IsOutdated)
        {
            Log(mLocalFile + "File is Downloaded.");
            return;
        }
        else if (localFileSize > mRemoteFileSize || IsOutdated)
        {
            if (!IsOutdated) Debug.LogWarning("Local file is larger than remote file, but not outdated. PANIC!");
            if (IsOutdated) Debug.Log("Local file is outdated, deleting");
            try
            {
                if (File.Exists(mLocalFile))
                    File.Delete(mLocalFile);
            }
            catch (System.Exception e)
            {
                Debug.LogWarning("<color=red>Could not delete local file</color>");
                Debug.LogError(e);
            }
            localFileSize = 0;
        }

        Log("[GetContent]localFileSize:" + localFileSize);

        int bufferSize = 1024 * 1000;
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(mRemoteFile);
        request.Timeout = 30000;
        request.AddRange((int)localFileSize, (int)mRemoteFileSize - 1);
        request.Method = WebRequestMethods.Http.Get;
        WebResponse res = request.GetResponse();

        Stream inStream = res.GetResponseStream();

        FileStream outStream = new FileStream(mLocalFile, (localFileSize > 0) ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite);

        int count = 0;
        byte[] buff = new byte[bufferSize];
        long downloadTotal = localFileSize;
        while ((count = inStream.Read(buff, 0, bufferSize)) > 0)
        {

            if (mAbort)
            {
                break;
            }

            outStream.Write(buff, 0, count);
            downloadTotal = downloadTotal + count;
            Log("downloadTotal:" + downloadTotal);
            process = (float)downloadTotal / (float)mRemoteFileSize;
            outStream.Flush();
        }

        Log("Read End.");

        outStream.Flush();
        outStream.Close();
        inStream.Close();
        request.Abort();
        Abort();
    }

    private void Log(object msg)
    {
        if (debug)
        {
            Debug.Log(msg);
        }
    }
}